Indice

  • Intro
    • Caso de uso
  • Shiny
    • micro-teoría
    • componentes
  • Manos a la obra: demo
  • Pero centrémonos en los gráficos y la visualización:
    • plotly, highcharter (render dinámico)
    • Cuándo usar cada una.

Caso de uso

  • Problemas:
    • Mucha información, poco espacio.
    • Hacer convivir el detalle con la impresión de conjunto.
  • Solución:
    • Interacción: ¿preguntas?, respuestas inmediatas
    • Explorar datos, mejora comprensión, promueve ciencia abierta y colaboración

Shiny: micro-teoría

ui + server + reactividad → render*()*Output()

# pseudo-esqueleto

ui <- fluidPage(
  sliderInput("n", "N:", 10, 100, 50), #input: control deslizante, llamado "n"
  plotOutput("p") #para visualizar el gráfico
)

server <- \(input, output, session){
  datos <- reactive({ rnorm(input$n) }) # función reactiva, depende de input$n para definir número de obs.
  output$p <- renderPlot({ hist(datos(), main= "Histograma", xlab="Datos", ylab="Frecuencia") }) # genera el gráfico "p"
}

shinyApp(ui, server)
expandir para código
DiagrammeR::grViz("
digraph shiny_diagram {
  rankdir=TB; // Dirección de arriba hacia abajo
  
  // Fondo general
  bgcolor='#F7F7F7';

  // Estilo de nodos
  graph [fontname='storia-sans'];
  node [shape=box, style=filled, fontname='storia-sans', fontsize=14, color=gray90];
  edge  [fontname='storia-sans', fontcolor=black, fontsize=12];
  
  // Cluster UI
  subgraph cluster_UI {
    label = 'UI (Frontend)';
    color = '#B03A2E'; // Color del borde del cluster
    style = rounded;
    fillcolor = '#F1948A'; // Fondo claro
    
    UI_input [label = 'Input', fillcolor='#9682fc50', color='#9682fc'];
    UI_output [label = 'Output', fillcolor='#01c9ad50', color='#01c9ad'];
  }

  // Nodo del servidor
  SERVER [label = 'Server (Backend)', shape=ellipse, fillcolor='#F1948A', color='#619CFF', style=solid];

  // Conexiones con etiquetas
  UI_input -> SERVER [label = 'Datos del\nusuario', fontname='storia-sans', fontcolor=black, fontsize=12];
  SERVER -> UI_output [label = 'Resultados', fontname='storia-sans', fontcolor=black, fontsize=12];

  // Alineación lógica
  {rank=same; UI_input; UI_output;}
}
")

Esquema: Estructura y reactividad

Algunos ejemplos

Hacer una imágen dinámica (1)

df <- tibble::tibble( #generamos una base de datos
  categoria = c("Antidepresivos", "Marihuana", "Ansiolíticos", "Alcohol", 
                "Hipnóticos", "Cocaína"), n = c(120, 90, 70, 25, 18, 10))
plotly::plot_ly( #generamos la primera entrada del gráfico interactivo
  df, #defino la base de datos
  labels = ~categoria, #donde se encuentra la etiqueta de las categorías y a qué columna refiere en la base de datos. Nótese la virgulilla
  values = ~n, #donde se encuentra el valor numérico y a qué columna refiere en la base de datos
  type   = "pie", #tipo de gráfico. EN este caso, de torta
  textinfo = "label+percent", #qué información mostrar en el gráfico
  hovertemplate = "<b>%{label}</b><br>N: %{value}<extra></extra>", #formato del tooltip (lo que aparece al posar el mouse sobre un sector)
  textfont        = list(family = "storia-sans, sans-serif"), #fuentes del texto dentro/afuera de la torta
  insidetextfont  = list(family = "storia-sans, sans-serif"), 
  outsidetextfont = list(family = "storia-sans") 
) |> #sintaxis pipe, que nos permite encadenar funciones
  plotly::layout(title = "'¿Qué sustancia consume semanalmente?'", font=list(family="storia-sans"))|>  #título del gráfico y fuente personalizada
  plotly::layout(legend = list(title = list(text = "<b> Categorías </b>")))|> #título de la leyenda. las b negritas (bold) se hacen con html
  layout( #otras opciones de formato
    font=list(family="storia-sans"), # fuente personalizada
    paper_bgcolor = "rgba(0,0,0,0)", plot_bgcolor  = "rgba(0,0,0,0)") # → fondo del lienzo y del área de trazado

Hacer una imágen dinámica (2)

# --- Datos FICTICIOS ---
datos <- tibble::tibble(candidato = c("Kast", "Jara", "Kaiser", "Mathei"), recuento_salud = c(48, 62, 15, 51))
# --- Gráfico de barras ---
highcharter::hchart(datos, #datos
  type = "column", #tipo de gráfico, por barras
  highcharter::hcaes(x = candidato, y = recuento_salud) #definimos las aes: eje x y eje y
) |> #sintaxis pipe, que nos permite encadenar funciones
  highcharter::hc_title(text = "Recuento de la palabra 'salud' en programas (ficticio)") |> #título del gráfico
  highcharter::hc_yAxis(title = list(text = "Número de menciones")) |> #eje y, etiqueta
  highcharter::hc_xAxis(title = list(text = "Candidaturas")) |> #eje x, etiqueta
  highcharter::hc_tooltip(pointFormat = "<b>{point.y}</b> menciones") |> #formato del tooltip (lo que aparece al posar el mouse sobre una barra): número de menciones en negrita (bold)
  highcharter::hc_plotOptions(column = list(# opciones de formato específico para gráfico de barras
      borderWidth = 0, #sin borde
      dataLabels = list(enabled = TRUE))) |># mostrar valor encima de barra
  highcharter::hc_chart(backgroundColor = "rgba(0,0,0,0)") |> #color de fondo trasparente
  highcharter::hc_add_theme(highcharter::hc_theme(chart = list(style = list(fontFamily = "storia-sans")))) |> #definir fuente personalizada
  highcharter::hc_exporting(enabled = TRUE) #habilitar exportación

Hacer una imágen dinámica (3)

expandir para código
# Datos tipo "tibble" (generados de forma reproducible)
set.seed(123)
fechas <- seq(as.Date("2017-11-01"), as.Date("2023-02-01"), by = "1 month")
n <- length(fechas)

# Series que imitan patrones y rangos de IVE en el período (verde ~40–70; azul ~2–16)
serie_verde <- round(55 + 12*sin(2*pi*(1:n)/12) + 6*rnorm(n)) |> pmax(38) |> pmin(70)
serie_azul  <- round( 9 +  4*sin(2*pi*(1:n)/12 + 1.2) + 3*rnorm(n)) |> pmax(2)  |> pmin(16)

datos <- tibble::tibble(
  mes = fechas,
  verde = serie_verde,
  azul  = serie_azul
) |>
  dplyr::mutate(mes_anio = format(mes, "%b %Y")) |>
  dplyr::select(mes, mes_anio, verde, azul)
p3<- 
ggplot2::ggplot(datos, ggplot2::aes(x = mes)) + #formato wide. cada variable es una columna, en este caso
  geom_line(ggplot2::aes(y = verde, color = "Interrupciones"), size = 1) + #añadimos una capa de línea con las interrupciones
  geom_line(ggplot2::aes(y = azul, color = "Continuaciones"), size = 1) + #añadimos una capa de línea con las continuaciones
  scale_color_manual(#generamos la leyenda
    name = "Leyenda",#título de la leyenda
    values = c("Interrupciones" = "#01c9ad", "Continuaciones" = "#9682fc"))+#colores de las líneas
  labs(y = "Número de casos", x = "Fecha")+ #Definimos las etiquetas de ejes
  theme_minimal(base_family = "storia-sans") #+ #tema minimalista, con la fuente personalizada
ggplotly(p3) |> #convertimos a plotly. ojo que el tooltip se genera por defecto, pero se puede personalizar
  layout(font=list(family="storia-sans"), # fuente personalizada
         paper_bgcolor = "rgba(0,0,0,0)",  plot_bgcolor  = "rgba(0,0,0,0)") # → fondo del lienzo y fondo del área de trazado

Recuento mensual de interrupciones y continuaciones de embarazo ficticio (azul=continuar)

Consideraciones sobre Shiny

  • Requiere conocimientos en HTML y CSS para personalizaciones avanzadas.

  • Shiny es una aplicación web: pensar en usuarios, inputs, outputs, validaciones, errores.

  • Al funcionar como aplicación independiente, es importante considerar recursos de despliegue y alojamiento.

  • Para auditar (logger) + logs más detallados: options(shiny.fullstacktrace = TRUE)

Aplicaciones más allá del módulo

  • ShinyQDA: Aplicación para análisis cualitativo de datos.

  • Shinydashboard: Paquete para crear dashboards interactivos con Shiny.

  • Flexdashboard: Paquete para crear dashboards flexibles y responsivos.

  • R Shiny Gallery: Colección de ejemplos y aplicaciones Shiny.

  • shinytest2: Paquete para pruebas automatizadas de aplicaciones Shiny.

  • Asistente Shiny (AI): Herramienta para generar código Shiny utilizando inteligencia artificial.

Nos vemos en clase!

Si le interesa:

  • Descargue el código fuente desde este este script

  • Genere una aplicación en Shiny

  • Explore paso por paso e indique qué se hizo

Fuentes

  • Breuer, J., & Aust, F. (2022, 27-28 de Abril). Reproducible research workflows for psychologists: Other topics in reproducible research [Presentation]. KU Leuven. Obtenido desde: https://frederikaust.com/reproducible-research-practices-workshop/slides/7_Other_Topics.html

  • Wembo, J. (2024, 24 de Septiembre). Learn Docker. DataCamp. https://www.datacamp.com/blog/learn-docker

  • Plaza-Vega, F. (2024). Mini curso: Quarto y GitHub Pages. III Jornadas de Ingeniería Estadística 202, 11 y 12 de Noviembre 2024, Auditorio DMCC Universidad de Santiago de Chile. https://github.com/FranPlaza/Quarto-Github

  • Xie, Y. (2024). Dynamic Documents with R and Quarto (2nd ed.). Chapman and Hall/CRC. https://quarto.org

  • The Jumping Rivers Blog. (2025, 30 de junio). Building trust with code: Validating Shiny apps in regulated environments. R-Bloggers. https://www.r-bloggers.com/2025/06/building-trust-with-code-validating-shiny-apps-in-regulated-environments-2/

  • Tutorial oficial de Shiny. (s.f.). Shiny from RStudio. Obtenido 04 de Noviembre de 2025, desde https://shiny.posit.co/r/getstarted/

  • Galería de ejemplos de Shiny. (s.f.). Shiny from RStudio. Obtenido 04 de Noviembre de 2025, desde https://shiny.posit.co/gallery/

  • Wickham, H. (2021). Mastering Shiny [versión en línea]. Recuperado el 3 de noviembre de 2025, de https://mastering-shiny.org/